home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Development Tools & Languages / AppsToGo / DTS.Lib / Print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  10.9 KB  |  394 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:     DTS.Lib
  5. ** File:        print.c
  6. ** Written by:  Eric Soldan
  7. ** Based on:    Code from Pete "Luke" Alexander.
  8. **
  9. ** Copyright © 1989-1991 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21.  
  22.  
  23. /*****************************************************************************/
  24.  
  25.  
  26.  
  27. #include "DTS.Lib2.h"
  28. #include "DTS.Lib.protos.h"
  29.  
  30. #ifndef __ERRORS__
  31. #include <Errors.h>
  32. #endif
  33.  
  34. #ifndef __RESOURCES__
  35. #include <Resources.h>
  36. #endif
  37.  
  38. #ifndef __STRINGUTILS__
  39. #include "StringUtils.h"
  40. #endif
  41.  
  42.  
  43.  
  44. /*****************************************************************************/
  45.  
  46.  
  47.  
  48. static pascal void    PrintIdleProc(void);
  49. short                gPrintPage;
  50. static DialogPtr    gPrintingStatusDialog;
  51.  
  52.  
  53.  
  54. /*****************************************************************************/
  55. /*****************************************************************************/
  56.  
  57. #ifdef applec
  58. #pragma segment ATGPrint
  59. #endif
  60.  
  61. /*****************************************************************************/
  62. /*****************************************************************************/
  63.  
  64.  
  65.  
  66. /* This print-loop function is designed to be called under various situations.
  67. ** The big issue that it handles is finder printing.  If multiple documents
  68. ** are to be printed from the finder, the user should only see one job dialog
  69. ** for all the files.  (If a job dialog is shown for each file, how does the
  70. ** user know for which file the dialog is for?)  So, for situations where
  71. ** there is more than one file to be printed, call this code the first time
  72. ** with the firstJob boolean true.  Normally, the jobDlg boolean will also
  73. ** be true, except that under 7.0, you may be printing in the background.
  74. ** If this is the case, you don't want a job dialog for even the first file,
  75. ** and you should pass in false for the jobDlg boolean in this case.  For
  76. ** files 2-N, you should pass false for both booleans.  For regular application
  77. ** printing, you should pass true for both booleans, since the file is the
  78. ** first (only) file, and you are not in the background.
  79. **
  80. ** After calling this function to print a document, you need to call it
  81. ** again with a nil document handle.  The print record for the first (or only)
  82. ** document printed is preserved in a static variable.  This is so that the
  83. ** job dialog information can be passed on to documents 2-N in the print job.
  84. ** Calling this function with the document handle nil tells this function
  85. ** that you are done printing documents, and that the print record for the
  86. ** first job can be disposed of. */
  87.  
  88. OSErr    PrintDocument(FileRecHndl frHndl, Boolean jobDlg, Boolean firstJob)
  89. {
  90.     OSErr            err;
  91.     THPrint            prRecHndl;
  92.     TPPrPort        printPort;
  93.     GrafPtr            oldPort;
  94.     short            i, keepResFile, copies, fstPage, lstPage;
  95.     TPrStatus        status;
  96.     ControlHandle    proceedButton;
  97.     Rect             rct;
  98.     Handle            txtHndl;
  99.     Str255            txt, txt2;
  100.     PrIdleUPP        pidleupp;
  101.  
  102.     static THPrint    prMergeHndl;
  103.  
  104.     if (!frHndl) {
  105.         if (prMergeHndl) {
  106.             DisposeHandle((Handle)prMergeHndl);
  107.             prMergeHndl = nil;
  108.         }
  109.         return(noErr);
  110.     }
  111.  
  112.     gPrintingStatusDialog = nil;
  113.  
  114.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  115.         /* If we can't generate a print record handle, we are out of here. */
  116.  
  117.     BlockMove((Ptr)&((*frHndl)->d.doc.fhInfo.print), (Ptr)(*prRecHndl), sizeof(TPrint));
  118.         /* Get the document's print info into the print record handle. */
  119.  
  120.     GetPort(&oldPort);
  121.  
  122.     DoSetCursor(&qd.arrow);
  123.  
  124.     keepResFile = CurResFile();
  125.     PrOpen();
  126.     err = PrError();
  127.  
  128.     if (!err) {
  129.         if (!(*frHndl)->d.doc.fhInfo.printRecValid) {
  130.             PrintDefault(prRecHndl);            /* The document print record was never 
  131.             err = PrError();                    ** initialized.  Now is is. */
  132.         }
  133.         if (!err) {
  134.             PrValidate(prRecHndl);        /* Do this just 'cause Apple says so. */
  135.             err = PrError();
  136.         }
  137.         if (!err) {
  138.             if (jobDlg) {                /* User gets to click some buttons. */
  139.                 UnhiliteWindows();
  140.                 if (!(PrJobDialog(prRecHndl)))
  141.                     err = userCanceledErr;
  142.                 else
  143.                     err = PrError();
  144.                 HiliteWindows();
  145.             }
  146.         }
  147.         if (!err) {
  148.             if (!firstJob) {
  149.                 fstPage = (*prMergeHndl)->prJob.iFstPage;
  150.                 lstPage = (*prMergeHndl)->prJob.iLstPage;
  151.                 PrJobMerge(prMergeHndl, prRecHndl);
  152.                 (*prMergeHndl)->prJob.iFstPage = (*prRecHndl)->prJob.iFstPage = fstPage;
  153.                 (*prMergeHndl)->prJob.iLstPage = (*prRecHndl)->prJob.iLstPage = lstPage;
  154.                 err = PrError();
  155.                     /* For documents other than the first, do the PrJobMerge thing.
  156.                     ** Unfortunately, PrJobMerge is kind of broken.  The first and last
  157.                     ** page fields have to be cached and put back.  The rest of PrJobMerge
  158.                     ** seems to work okay. */
  159.             }
  160.         }
  161.  
  162.         if (!err) {            /* Put the defaulted/validated/jobDlg'ed print record in the doc. */
  163.             pidleupp = nil;
  164.             fstPage = (*prRecHndl)->prJob.iFstPage;
  165.             lstPage = (*prRecHndl)->prJob.iLstPage;
  166.             copies  = (*prRecHndl)->prJob.iCopies;
  167.             BlockMove((Ptr)(*prRecHndl), (Ptr)&((*frHndl)->d.doc.fhInfo.print), sizeof(TPrint));
  168.             (*frHndl)->d.doc.fhInfo.printRecValid = true;
  169.  
  170.             gPrintingStatusDialog = nil;
  171.             i = ((*prRecHndl)->prStl.wDev >> 8) & 0xFF;
  172.             if ((i == 1) || (i == 2))
  173.                 gPrintingStatusDialog = GetNewDialog(rPrStatusDlg, nil, (WindowPtr)-1);
  174.             if (gPrintingStatusDialog) {
  175.                     /* The ImageWriter driver uses ParamText, so we can’t.
  176.                     ** If we try to, then the printer name shows up, instead of
  177.                     ** the document name.  Due to this, we have to parse our
  178.                     ** own text.  We expect dialog item#4 to have a c/r in it.
  179.                     ** We use the c/r instead of ^0, due to the ImageWriter driver.
  180.                     ** We just replace the c/r with the name of the document. */
  181.                 GetDialogItem(gPrintingStatusDialog, 4, &i, (Handle *)&txtHndl, &rct);
  182.                 GetDialogItemText(txtHndl, txt);
  183.                 for (i = *txt; i; --i) {
  184.                     if (txt[i] == 13) {
  185.                         txt[i] = *txt - i;
  186.                         txt[0] = i - 1;
  187.                         break;
  188.                     }
  189.                 }        /* We now have two pascal strings -- one right after the other. */
  190.                 pcpy(txt2, txt);                                /* Copy the first string. */
  191.                 pcat(txt2, (*frHndl)->fileState.fss.name);        /* Append the document name. */
  192.                 pcat(txt2, txt + *txt + 1);                        /* Append the second string. */
  193.                 SetDialogItemText(txtHndl, txt2);
  194.                 GetDialogItem(gPrintingStatusDialog, 1, &i, (Handle *)&proceedButton, &rct);
  195.                 HiliteControl(proceedButton, 255);
  196.                     /* Setup the proceed/pause/cancel dialog with the document name. */
  197.                 pidleupp = NewPrIdleProc(PrintIdleProc);
  198.                 (*prRecHndl)->prJob.pIdleProc = pidleupp;
  199.                 UseResFile(keepResFile);        /* Hook in the proceed/pause/cancel dialog. */
  200.                 UnhiliteWindows();
  201.             }
  202.  
  203.             for (i = 1; (i <= copies) && (!err); ++i) {
  204.  
  205.                 printPort = PrOpenDoc(prRecHndl, nil, nil);
  206.                 if (!(err = PrError())) {
  207.  
  208.                     gPrintPage = 1;
  209.                     while (gPrintPage <= lstPage) {
  210.  
  211.                         PrOpenPage(printPort, nil);
  212.  
  213.                         if (!(err = PrError()))
  214.                             err = DoImageDocument(frHndl);
  215.                                 /* Do the print thing here. */
  216.  
  217.                         PrClosePage(printPort);
  218.  
  219.                         if (!gPrintPage) break;
  220.                         ++gPrintPage;
  221.                     }
  222.                     gPrintPage = 0;
  223.                 }
  224.                 PrCloseDoc(printPort);
  225.             }
  226.             if (pidleupp) {
  227.                 DisposeRoutineDescriptor(pidleupp);
  228.             }
  229.         }
  230.  
  231.         if (
  232.             (!err) &&
  233.             ((*prRecHndl)->prJob.bJDocLoop == bSpoolLoop) &&
  234.             (!(err = PrError()))
  235.         ) {
  236.             PrPicFile(prRecHndl, nil, nil, nil, &status);
  237.             err = PrError();
  238.         }
  239.     }
  240.  
  241.     if (firstJob)
  242.         prMergeHndl = prRecHndl;
  243.     else
  244.         DisposeHandle((Handle)prRecHndl);
  245.  
  246.     if (gPrintingStatusDialog)
  247.         DisposeDialog(gPrintingStatusDialog);
  248.  
  249.     PrClose();
  250.     UseResFile(keepResFile);
  251.  
  252.     SetPort(oldPort);
  253.     HiliteWindows();
  254.  
  255.     if (err == iIOAbortErr)
  256.         err = noErr;
  257.  
  258.     return(err);
  259. }
  260.  
  261.  
  262.  
  263. /*****************************************************************************/
  264.  
  265.  
  266.  
  267. /* DonePrinting makes sure that PrintDocument gets rid of the prMergeHndl
  268. ** print record that is used for multiple document printing.  Call this after
  269. ** or the last document is printed, or you get a memory leak. */
  270.  
  271. void    DonePrinting(void)
  272. {
  273.     PrintDocument(nil, false, false);
  274. }
  275.  
  276.  
  277.  
  278. /*****************************************************************************/
  279.  
  280.  
  281.  
  282. /* PrintIdleProc will handle events in the 'Printing Status Dialog' which
  283. ** gives the user the option to 'Proceed', 'Pause', or 'Cancel' the current
  284. ** printing job during print time.
  285. **
  286. ** The buttons:
  287. **        1: Proceed
  288. **        2: Pause
  289. **        3: Cancel
  290. */
  291.  
  292. pascal void    PrintIdleProc(void)
  293. {
  294.     Boolean                button, paused;
  295.     ControlHandle        pauseButton, proceedButton;
  296.     DialogPtr            aDialog;
  297.     EventRecord            anEvent;
  298.     GrafPtr                oldPort;
  299.     Rect                 rct;
  300.     short                item, itemType, keepResFile;
  301.  
  302.     GetPort(&oldPort);
  303.  
  304.     UseResFile(keepResFile = CurResFile());
  305.  
  306.     GetDialogItem(gPrintingStatusDialog, 1, &itemType, (Handle *)&proceedButton, &rct);
  307.     HiliteControl(proceedButton, 255);
  308.     GetDialogItem(gPrintingStatusDialog, 2, &itemType, (Handle *)&pauseButton, &rct);
  309.  
  310.     paused = false;
  311.     do {
  312.         if (GetNextEvent((mDownMask + mUpMask + updateMask), &anEvent)) {
  313.             if (gPrintingStatusDialog != FrontWindow())
  314.                 SelectWindow(gPrintingStatusDialog);
  315.  
  316.             if (IsDialogEvent(&anEvent)) {
  317.                 button = DialogSelect(&anEvent, &aDialog, &item);
  318.  
  319.                 if ((button) && (aDialog == gPrintingStatusDialog)) {
  320.                     switch (item) {
  321.                         case 1:
  322.                             HiliteControl(pauseButton, 0);        /* Enable PAUSE    */
  323.                             HiliteControl(proceedButton, 255);    /* Disable PROCEED */
  324.                             paused = false;
  325.                             break;
  326.                         case 2:
  327.                             HiliteControl(pauseButton, 255);    /* Disable PAUSE  */
  328.                             HiliteControl(proceedButton, 0);    /* Enable PROCEED */
  329.                             paused = true;
  330.                             break;
  331.                         case 3:
  332.                             PrSetError(iPrAbort);               /* CANCEL printing */
  333.                             paused = false;
  334.                             break;
  335.                     }
  336.                 }
  337.             }
  338.         }
  339.     } while (paused != false); 
  340.  
  341.     SetPort(oldPort);
  342. }
  343.  
  344.  
  345.  
  346. /*****************************************************************************/
  347.  
  348.  
  349.  
  350. /* Call this from the application to present a style dialog.  The changes are
  351. ** automatically saved in the document. */
  352.  
  353. OSErr    PresentStyleDialog(FileRecHndl frHndl)
  354. {
  355.     OSErr        err;
  356.     THPrint        prRecHndl;
  357.     short        oldRes;
  358.  
  359.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  360.  
  361.     oldRes = CurResFile();
  362.     PrOpen();
  363.  
  364.     if (!(err = PrError())) {
  365.  
  366.         BlockMove((Ptr)&(*frHndl)->d.doc.fhInfo.print, (Ptr)*prRecHndl, sizeof(TPrint));
  367.             /* Get data, valid or not. */
  368.  
  369.         if (!(*frHndl)->d.doc.fhInfo.printRecValid)
  370.             PrintDefault(prRecHndl);
  371.         else
  372.             PrValidate(prRecHndl);
  373.  
  374.         if (!(err = PrError())) {
  375.             UnhiliteWindows();
  376.             if (PrStlDialog(prRecHndl)) {
  377.                 BlockMove((Ptr)*prRecHndl, (Ptr)&(*frHndl)->d.doc.fhInfo.print, sizeof(TPrint));
  378.                 (*frHndl)->d.doc.fhInfo.printRecValid = true;
  379.             }
  380.             else err = userCanceledErr;
  381.             HiliteWindows();
  382.         }
  383.     }
  384.  
  385.     DisposeHandle((Handle)prRecHndl);
  386.     PrClose();
  387.     UseResFile(oldRes);
  388.  
  389.     return(err);
  390. }
  391.  
  392.  
  393.  
  394.